package com.qf.shiro;

import com.qf.entity.Role;
import com.qf.entity.User;
import com.qf.service.PermissionService;
import com.qf.service.RoleService;
import com.qf.service.UserService;
import com.qf.service.impl.PermissionServiceImpl;
import com.qf.service.impl.RoleServiceImpl;
import com.qf.service.impl.UserServiceImpl;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import java.util.HashSet;
import java.util.Set;

public class CustomRealm extends AuthorizingRealm {

    public static void main(String[] args) {
        String md5Hash = new Md5Hash("admin","sdfhgodpdsidhjvasjdjbljofhj",1024).toString();
        System.out.println(md5Hash);
    }


    {
        // 密码加密方式
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("MD5");
        matcher.setHashIterations(1024);
        this.setCredentialsMatcher(matcher);
    }

    private UserService userService = new UserServiceImpl();

    private RoleService roleService = new RoleServiceImpl();

    private PermissionService permissionService = new PermissionServiceImpl();

    // 认证,只需要检验用户名正确即可,密码的校验,封装到AuthenticationInfo中,让shiro校验
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //1. 通过token获取用户名
        String username = (String) token.getPrincipal();

        //2. 通过用户名查询当前用户信息
        User user = userService.findByUsername(username);

        //3. 判断用户信息是否为null // UnknownAccountException
        if(user == null){
            // 可以手动抛出异常
            throw new UnknownAccountException("用户名不正确!");
        }

        //4. 封装AuthenticationInfo对象,用户信息和密码存入info对象中
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),"我的自定义Realm");

        //5. 设置盐
        info.setCredentialsSalt(ByteSource.Util.bytes(user.getSalt()));

        //6. 返回
        return info;   // shiro会将用户输入的密码进行MD5加密1024次,并且再根据指定的salt对加密过后的密码,再加盐.
    }


    // 授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //1. 获取在认证操作中,设置给info对象的第一个参数数据
        User user = (User) principals.getPrimaryPrincipal();

        //2.1 根据用户信息,查询出当前用户拥有的全部角色
        Set<Role> roles = roleService.findAllRolesByUserId(user.getId());
        //2.2 将roles封装为roleNames的Set集合
        Set<String> roleNames = new HashSet<>();
        for (Role role : roles) {
            roleNames.add(role.getRoleName());
        }

        //3. 根据全部角色查询当前用户拥有的全部权限/菜单.
        Set<String> permNames = permissionService.findAllPermsByRoleId(roles);

        //4. 将角色信息和权限信息全部封装到AuthorizationInfo对象中
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(roleNames);
        info.setStringPermissions(permNames);

        //5. 返回
        return info;
    }

}
